- Miguel Vargas (lvc0107@protonmail.com)
En este laboratorio les tocarÔ probar con distintos parÔmetros de los algoritmos de aprendizaje automÔtico aprendidos hasta ahora. La idea es que vean como la selección de atributos, el cambio de hiperparÔmetros, y los distintos algoritmos afectan los resultados de un regresor o clasificador sobre un conjunto de datos.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap
from sklearn.datasets import load_boston, load_breast_cancer, load_iris
from sklearn.linear_model import LinearRegression, LogisticRegression, Perceptron, Ridge
from sklearn.metrics import accuracy_score, confusion_matrix, mean_squared_error
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import PolynomialFeatures
from ml.visualization import plot_confusion_matrix, classifier_boundary
np.random.seed(1234) # Setup seed to be more deterministic
%matplotlib inline
boston_data = load_boston()
len(boston_data['data'])
Como el dataset de boston tiene 506 muestras, generamos 506 indices aleatoriamente para luego obtener dos subsets de 80% y 20% del dataset desordenados
np.random.permutation(506)
# Utilizamos aproximadamente 80% de los datos para entrenamiento y 20% para validación
shuff_data = np.random.permutation(506)
shuff_train = shuff_data[:400]
shuff_val = shuff_data[400:]
X_train = boston_data['data'][shuff_train]
X_val = boston_data['data'][shuff_val]
y_train = boston_data['target'][shuff_train]
y_val = boston_data['target'][shuff_val]
# Necesario para poder hacer un regresor por feature
feature_map = {feature: idx for idx, feature in enumerate(boston_data['feature_names'])}
feature_map
print(boston_data['DESCR'])
Para revisar cómo afecta el cambio de parĆ”metros y los distintos tipos de regresores y atributos (caracterĆsticas) al resultado final del algoritmo de aprendizaje automĆ”tico, lo que se va a hacer es entrenar el regresor tomando sólo un atributo y visualizar eso.
Se busca entrenar utilizando el conjunto de entrenamiento (el terminado en train) y evaluar utilizando el conjunto de validación (el terminado en val). Luego se visualiza la función calculada para cada conjunto y se la compara.
Los atributos posibles estÔn listados en la descripción del conjunto de datos en la celda anterior. No todos son útiles para visualizar, en particular solo nos interesan los atributos numéricos y descartamos los atributos que se listan a continuación:
CHAS: Atributo categórico (toma valor 0 o 1).RAD: Atributo categórico (Ćndice).MEDV: Este valor se lo lista como atributo en la descripción del conjunto de datos pero en realidad es el valor de y, i.e. es el valor que tratamos de aproximar con el algoritmo de aprendizaje automĆ”tico.# Seleccionamos un atributo de los listados en la descripción que no sea categórico
selected_feature = 'AGE'
numeric_features = ['AGE', 'CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'DIS', 'TAX', 'PTRATIO', 'B', 'LSTAT']
feature_col = feature_map[selected_feature]
feature_col
X_train[:, feature_col] # Vemos datos de AGE para entrenamiento
X_train_feature = X_train[:, feature_col].reshape(-1, 1) # Hay que ser que sea una matriz no un vector para que funcione con scikit learn
type(X_train_feature)
X_train_feature.shape
# reshape(-1, 1) fransforma el vector en una matriz de una columna y (-1) filas.
# -1 significa indeterminado, entonces numpy resuelve que la cantidad de filas es igual al numero de elementos
# en el vector, en este caso 400.
X_val_feature = X_val[:, feature_col].reshape(-1, 1)
# Entrenamos un clasificador utilizando sólo ese atributo sobre el conjunto de entrenamiento (X_train, y_train)
model = LinearRegression()
model.fit(X_train_feature, y_train)
# Evaluamos el desempeƱo del clasificador utilizando la media del error cuadrado (MSE o mean squared error)
# sobre el conjunto de datos de entrenamiento (X_train, y_train) y lo comparamos con el de validación (X_val, y_val)
# Mientras mƔs cercano a cero mejor
print('Media del error cuadrado para entrenamiento: %.2f' %
mean_squared_error(y_train, model.predict(X_train_feature)))
print('Media del error cuadrado para validación: %.2f' %
mean_squared_error(y_val, model.predict(X_val_feature)))
def plot_lineal_regression(X_train_feature, y_train, X_val_feature, y_val, selected_feature):
plt.figure(figsize=(14, 5), dpi= 80, facecolor='w', edgecolor='k')
X_range_start = np.min(np.r_[X_train_feature, X_val_feature])
X_range_stop = np.max(np.r_[X_train_feature, X_val_feature])
y_range_start = np.min(np.r_[y_train, y_val])
y_range_stop = np.max(np.r_[y_train, y_val])
X_linspace = np.linspace(X_range_start, X_range_stop, 200).reshape(-1, 1)
# Conjunto de entrenamiento
plt.subplot(1, 2, 1)
plt.scatter(X_train_feature, y_train, facecolor="dodgerblue", edgecolor="k", label="datos")
plt.plot(X_linspace, model.predict(X_linspace), color="tomato", label="modelo")
plt.ylim(y_range_start, y_range_stop)
plt.title(f"Conjunto de Entrenamiento para feature {selected_feature}")
# Conjunto de validación
plt.subplot(1, 2, 2)
plt.scatter(X_val_feature, y_val, facecolor="dodgerblue", edgecolor="k", label="datos")
plt.plot(X_linspace, model.predict(X_linspace), color="tomato", label="modelo")
plt.ylim(y_range_start, y_range_stop)
plt.title(f"Conjunto de Validación para feature {selected_feature}")
plt.show()
mean_squared_training_error = mean_squared_error(y_train, model.predict(X_train_feature))
print(f'Media del error cuadrado para entrenamiento del feature {selected_feature} : {mean_squared_training_error:.2f}')
mean_squared_val_error = mean_squared_error(y_val, model.predict(X_val_feature))
print(f'Media del error cuadrado para validación del feature {selected_feature} : {mean_squared_val_error:.2f}')
plot_lineal_regression(X_train_feature, y_train, X_val_feature, y_val, selected_feature)
El scatter plot muestra que el feature AGE tiene datos demasiado dispersos y que en principio no se ajusta bien con un polinomio de grado 1 (recta). No parece que se puedan ajustar bien tampoco con una regression polinomial. Analizamos el resto de los features:
for selected_feature in set(numeric_features) - {'AGE'}:
feature_col = feature_map[selected_feature]
X_train_feature = X_train[:, feature_col].reshape(-1, 1) # Hay que haceer que sea una matriz, no un vector para que funcione con scikit learn
X_val_feature = X_val[:, feature_col].reshape(-1, 1)
model = LinearRegression()
model.fit(X_train_feature, y_train)
plot_lineal_regression(X_train_feature, y_train, X_val_feature, y_val, selected_feature)
Se observa que los features no se ajustan a una función lineal
Analizamos el feature LSTAT
selected_feature = 'LSTAT'
feature_col = feature_map[selected_feature]
X_train_feature = X_train[:, feature_col].reshape(-1, 1)
X_val_feature = X_val[:, feature_col].reshape(-1, 1)
def get_mean_squared_error_for_lineal_regression(X_train_feature, y_train, X_val_feature, y_val, polynomial_degree):
"""
Get mean squared error for traning and validation set in a linear regression model
"""
poly_features = PolynomialFeatures(polynomial_degree)
poly_features.fit(X_train_feature)
X_poly_train = poly_features.transform(X_train_feature)
X_poly_val = poly_features.transform(X_val_feature)
model = LinearRegression()
model.fit(X_poly_train, y_train)
mean_squared_training_error = mean_squared_error(y_train, model.predict(X_poly_train))
mean_squared_val_error = mean_squared_error(y_val, model.predict(X_poly_val))
return mean_squared_training_error, mean_squared_val_error
# Evaluate until large polinomial degree in order to detect overfitting
x = range(1, 50)
errors_training = []
errors_val = []
for degree in x:
train_error, val_error = get_mean_squared_error_for_lineal_regression(X_train_feature,
y_train,
X_val_feature,
y_val,
degree)
errors_training.append(train_error)
errors_val.append(val_error)
plt.figure(figsize=(14, 5), dpi= 80, facecolor='w', edgecolor='k')
plt.plot(x, errors_training, label='Training')
plt.plot(x, errors_val, label='Validation')
plt.title(f" Mean squared error for feature {selected_feature}")
plt.legend(loc='upper right')
plt.xlabel("degree")
plt.ylabel("Mean squared error")
plt.show()
x = range(1, 10)
errors_training = []
errors_val = []
for degree in x:
train_error, val_error = get_mean_squared_error_for_lineal_regression(X_train_feature,
y_train,
X_val_feature,
y_val,
degree)
errors_training.append(train_error)
errors_val.append(val_error)
plt.figure(figsize=(14, 5), dpi= 80, facecolor='w', edgecolor='k')
plt.plot(x, errors_training, label='Training')
plt.plot(x, errors_val, label='Validation')
plt.title(f" Mean squared error for feature {selected_feature}")
plt.legend(loc='upper right')
plt.xlabel("degree")
plt.ylabel("Mean squared error")
plt.show()
Se observa que el error medio para el conjunto de validación alcanza su minĆmo para un polinomio de grado 7 No es necesario ajustar al modelo con polinomios mayores a ese grado.
for polynomial_degree in range(1, 9):
# Probamos distintos grados del polinomio
poly_features = PolynomialFeatures(polynomial_degree)
poly_features.fit(X_train_feature)
X_poly_train = poly_features.transform(X_train_feature)
X_poly_val = poly_features.transform(X_val_feature)
model = LinearRegression()
model.fit(X_poly_train, y_train)
plt.figure(figsize=(14, 5), dpi=80, facecolor='w', edgecolor='k')
X_range_start = np.min(np.r_[X_train_feature, X_val_feature])
X_range_stop = np.max(np.r_[X_train_feature, X_val_feature])
y_range_start = np.min(np.r_[y_train, y_val])
y_range_stop = np.max(np.r_[y_train, y_val])
X_linspace = np.linspace(X_range_start, X_range_stop, 200).reshape(-1, 1)
X_linspace_poly = poly_features.transform(X_linspace)
# Conjunto de entrenamiento
plt.subplot(1, 2, 1)
plt.scatter(X_train_feature, y_train, facecolor="dodgerblue", edgecolor="k", label="datos")
plt.plot(X_linspace, model.predict(X_linspace_poly), color="tomato", label="modelo")
plt.ylim(y_range_start, y_range_stop)
plt.title(f"Conjunto de Entrenamiento para feature {selected_feature} con grado {polynomial_degree}")
# Conjunto de validación
plt.subplot(1, 2, 2)
plt.scatter(X_val_feature, y_val, facecolor="dodgerblue", edgecolor="k", label="datos")
plt.plot(X_linspace, model.predict(X_linspace_poly), color="tomato", label="modelo")
plt.ylim(y_range_start, y_range_stop)
plt.title(f"Conjunto de Validación para feature {selected_feature} con grado {polynomial_degree}")
plt.show()
def get_mean_squared_error_for_lineal_regression_gridge(X_train_feature, y_train, X_val_feature, y_val, alpha):
"""
Get mean squared error for traning and validation set in a linear regression model plus regularization
"""
model = Ridge(alpha=alpha)
model.fit(X_train_feature, y_train)
mean_squared_training_error = mean_squared_error(y_train, model.predict(X_train_feature))
mean_squared_val_error = mean_squared_error(y_val, model.predict(X_val_feature))
return mean_squared_training_error, mean_squared_val_error
x = [pow(10, x) for x in list(range(-5, 5))]
errors_training = []
errors_val = []
for alpha in x:
train_error, val_error = get_mean_squared_error_for_lineal_regression_gridge(X_train_feature,
y_train,
X_val_feature,
y_val,
alpha)
errors_training.append(train_error)
errors_val.append(val_error)
plt.figure(figsize=(14, 5), dpi= 80, facecolor='w', edgecolor='k')
plt.plot(x, errors_training, label='Training')
plt.plot(x, errors_val, label='Validation')
plt.title(f" Mean squared error for feature {selected_feature}")
plt.legend(loc='upper right')
plt.xlabel("alpha")
plt.ylabel("Mean squared error")
plt.show()
x = [pow(10, x) for x in list(range(-1, 4))]
errors_training = []
errors_val = []
for alpha in x:
errors_training.append(get_mean_squared_error_for_lineal_regression_gridge(X_train_feature,
y_train,
X_val_feature,
y_val,
alpha)[0])
errors_val.append(get_mean_squared_error_for_lineal_regression_gridge(X_train_feature,
y_train,
X_val_feature,
y_val,
alpha)[1])
plt.figure(figsize=(14, 5), dpi= 80, facecolor='w', edgecolor='k')
plt.plot(x, errors_training, label='Training')
plt.plot(x, errors_val, label='Validation')
plt.title(f" Mean squared error for feature {selected_feature}")
plt.legend(loc='upper right')
plt.xlabel("alpha")
plt.ylabel("Mean squared error")
plt.show()
def plot_lineal_regression_ridge(X_train_feature, y_train, X_val_feature, y_val, selected_feature, alpha):
plt.figure(figsize=(14, 5), dpi= 80, facecolor='w', edgecolor='k')
X_range_start = np.min(np.r_[X_train_feature, X_val_feature])
X_range_stop = np.max(np.r_[X_train_feature, X_val_feature])
y_range_start = np.min(np.r_[y_train, y_val])
y_range_stop = np.max(np.r_[y_train, y_val])
X_linspace = np.linspace(X_range_start, X_range_stop, 200).reshape(-1, 1)
# Conjunto de entrenamiento
plt.subplot(1, 2, 1)
plt.scatter(X_train_feature, y_train, facecolor="dodgerblue", edgecolor="k", label="datos")
plt.plot(X_linspace, model.predict(X_linspace), color="tomato", label="modelo")
plt.ylim(y_range_start, y_range_stop)
plt.title(f"Conjunto de Entrenamiento para feature {selected_feature} con alpha en ridge {alpha}")
# Conjunto de validación
plt.subplot(1, 2, 2)
plt.scatter(X_val_feature, y_val, facecolor="dodgerblue", edgecolor="k", label="datos")
plt.plot(X_linspace, model.predict(X_linspace), color="tomato", label="modelo")
plt.ylim(y_range_start, y_range_stop)
plt.title(f"Conjunto de Validación para feature {selected_feature} con alpha en ridge {alpha}")
plt.show()
alpha = 1000 # ParÔmetro de regularización. También denominado como parÔmetro `lambda`.
model = Ridge(alpha=alpha)
model.fit(X_train_feature, y_train)
plot_lineal_regression_ridge(X_train_feature, y_train, X_val_feature, y_val, selected_feature, alpha)
No tiene mucho sentido aplicar el ridge a un polinomio de grado 1(pues no estamos suavizando nada) De echo con una recta tenemos un problema de underfitting y el ridge sirve para suavizar polinomios con grados altos, que ajustan muy bien en etapa de entrenamiento pero no en etapa de validación(overfitting)
Probamos con grado polinomio de grado 7 que fue el mejor resultado para regresion polinomial sin regularizacion
Probamos los siguientes valores para lambda(o alpha)
x = [pow(10, x) for x in list(range(-4, 5))]
x
polynomial_degree = 7
alpha = 100
poly_features = PolynomialFeatures(polynomial_degree)
poly_features.fit(X_train_feature)
X_poly_train = poly_features.transform(X_train_feature)
X_poly_val = poly_features.transform(X_val_feature)
model = Ridge(alpha=alpha)
model.fit(X_poly_train, y_train)
errors_training = []
errors_val = []
for alpha in x:
errors_training.append(get_mean_squared_error_for_lineal_regression_gridge(X_train_feature,
y_train,
X_val_feature,
y_val,
alpha)[0])
errors_val.append(get_mean_squared_error_for_lineal_regression_gridge(X_train_feature,
y_train,
X_val_feature,
y_val,
alpha)[1])
plt.figure(figsize=(14, 5), dpi= 80, facecolor='w', edgecolor='k')
plt.plot(x, errors_training, label='Training')
plt.plot(x, errors_val, label='Validation')
plt.title(f" Mean squared error for feature {selected_feature}")
plt.legend(loc='upper right')
plt.xlabel("alpha")
plt.ylabel("Mean squared error")
plt.show()
Se observa el mismo comportamiento del error con ridge para regression polinomial. No parece que el termino de regularización ayude mucho al ajuste de este feature.
alphas = [pow(10, x) for x in list(range(-4, 4))]
for alpha in alphas:
plt.figure(figsize=(14, 5), dpi= 80, facecolor='w', edgecolor='k')
polynomial_degree = 7
poly_features = PolynomialFeatures(polynomial_degree)
poly_features.fit(X_train_feature)
X_poly_train = poly_features.transform(X_train_feature)
X_poly_val = poly_features.transform(X_val_feature)
model = Ridge(alpha=alpha)
model.fit(X_poly_train, y_train)
X_range_start = np.min(np.r_[X_train_feature, X_val_feature])
X_range_stop = np.max(np.r_[X_train_feature, X_val_feature])
y_range_start = np.min(np.r_[y_train, y_val])
y_range_stop = np.max(np.r_[y_train, y_val])
X_linspace = np.linspace(X_range_start, X_range_stop, 200).reshape(-1, 1)
X_linspace_poly = poly_features.transform(X_linspace)
# Conjunto de entrenamiento
plt.subplot(1, 2, 1)
plt.scatter(X_train_feature, y_train, facecolor="dodgerblue", edgecolor="k", label="datos")
plt.plot(X_linspace, model.predict(X_linspace_poly), color="tomato", label="modelo")
plt.ylim(y_range_start, y_range_stop)
plt.title(f"Entrenamiento para feature {selected_feature} con alpha en ridge {alpha}")
# Conjunto de validación
plt.subplot(1, 2, 2)
plt.scatter(X_val_feature, y_val, facecolor="dodgerblue", edgecolor="k", label="datos")
plt.plot(X_linspace, model.predict(X_linspace_poly), color="tomato", label="modelo")
plt.ylim(y_range_start, y_range_stop)
plt.title(f"Validación para feature {selected_feature} con alpha en ridge {alpha}")
plt.show()
Se observa que para un polinomio de grado 7 un $\alpha$ bajo, parece ajustar un poco mejor que para valores altos
Analizamos otros features:
def plot_polinomial_regression_ridge(X_train_feature, y_train, X_val_feature, y_val, selected_feature, alpha):
plt.figure(figsize=(14, 5), dpi= 80, facecolor='w', edgecolor='k')
X_range_start = np.min(np.r_[X_train_feature, X_val_feature])
X_range_stop = np.max(np.r_[X_train_feature, X_val_feature])
y_range_start = np.min(np.r_[y_train, y_val])
y_range_stop = np.max(np.r_[y_train, y_val])
X_linspace = np.linspace(X_range_start, X_range_stop, 200).reshape(-1, 1)
X_linspace_poly = poly_features.transform(X_linspace)
# Conjunto de entrenamiento
plt.subplot(1, 2, 1)
plt.scatter(X_train_feature, y_train, facecolor="dodgerblue", edgecolor="k", label="datos")
plt.plot(X_linspace, model.predict(X_linspace_poly), color="tomato", label="modelo")
plt.ylim(y_range_start, y_range_stop)
plt.title(f"Conjunto de Entrenamiento para feature {selected_feature} con alpha en ridge {alpha}")
# Conjunto de validación
plt.subplot(1, 2, 2)
plt.scatter(X_val_feature, y_val, facecolor="dodgerblue", edgecolor="k", label="datos")
plt.plot(X_linspace, model.predict(X_linspace_poly), color="tomato", label="modelo")
plt.ylim(y_range_start, y_range_stop)
plt.title(f"Conjunto de Validación para feature {selected_feature} con alpha en ridge {alpha}")
plt.show()
for selected_feature in numeric_features:
feature_col = feature_map[selected_feature]
X_train_feature = X_train[:, feature_col].reshape(-1, 1) # Hay que ser que sea una matriz no un vector para que funcione con scikit learn
X_val_feature = X_val[:, feature_col].reshape(-1, 1)
for alpha in (0.1, 10000):
polynomial_degree = 11
poly_features = PolynomialFeatures(polynomial_degree)
poly_features.fit(X_train_feature)
X_poly_train = poly_features.transform(X_train_feature)
X_poly_val = poly_features.transform(X_val_feature)
model = Ridge(alpha=alpha)
model.fit(X_poly_train, y_train)
plot_polinomial_regression_ridge(X_train_feature, y_train, X_val_feature, y_val, selected_feature, alpha)
Luego de probar con polinomios de grado 11 y terminos de regularización pequeños y grandes, observamos que algunos features pueden ajustarse con un polinomio (por ejemplo RM) y otros features no se pueden ajustar correctamente ni alterando el ridge o variando el grado del polinomio, dado a que estan muy dispersos.
La clasificación binaria tiene dos posibles etiquetas para su clasificación: SI y NO (o 0 y 1, o -1 y 1). Nuevamente, se busca entrenar utilizando el conjunto de entrenamiento (el terminado en train) y evaluar utilizando el conjunto de validación (el terminado en val). Luego se visualiza la función calculada para cada conjunto y se la compara.
Similar al caso anterior, para poder visualizar los distintos atributos y cómo estos afectan el modelo, debemos hacer uso de una selección de atributos a mano. En este caso todos los atributos son vÔlidos, puesto que todos son numéricos. Como tenemos una clasificación, lo que buscamos ver es la frontera de decisión eligiendo distintos atributos y parÔmetros para distintos clasificadores. En este caso elegimos 2 atributos ya que la clase se representarÔ por color dentro del grÔfico.
breast_cancer_data = load_breast_cancer()
# Utilizamos aproximadamente 80% de los datos para entrenamiento y 20% para validación
shuff_data = np.random.permutation(569)
shuff_train = shuff_data[:400]
shuff_val = shuff_data[400:]
X_train = breast_cancer_data['data'][shuff_train]
X_val = breast_cancer_data['data'][shuff_val]
y_train = breast_cancer_data['target'][shuff_train]
y_val = breast_cancer_data['target'][shuff_val]
feature_map = {feature: idx for idx, feature in enumerate(breast_cancer_data['feature_names'])}
print(breast_cancer_data['DESCR'])
print("Listado de atributos\n====================")
for feature in breast_cancer_data['feature_names']:
print("- %s" % feature)
# Seleccionamos dos atributo de los listados en el apartado anterior, uno para el eje x y otro para el eje y
x_feature = 'mean radius'
y_feature = 'mean texture'
x_feature_col = feature_map[x_feature]
y_feature_col = feature_map[y_feature]
X_train_feature = X_train[:, [x_feature_col, y_feature_col]]
X_val_feature = X_val[:, [x_feature_col, y_feature_col]]
penalty = 'l1' # Tipo de regularización: l1 (valor absoluto), l2 (cuadrados), elasticnet (l1 + l2).
alpha = 0.1 # ParÔmetro de regularización. También denominado como parÔmetro `lambda`.
max_iter = 100 # Cantidad mƔxima de iteraciones del algoritmo
model = Perceptron(penalty=penalty, alpha=alpha, max_iter=max_iter)
model.fit(X_train_feature, y_train)
# Evaluamos el desempeƱo del clasificador utilizando la exactitud (accuracy) sobre el conjunto
# de datos de entrenamiento (X_train, y_train) y lo comparamos con el de validación (X_val, y_val)
# La exactitud toma valor en el rango [0, 1] donde mƔs alto es mejor
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
La matriz de confusión sirve en clasificación para ver que tanto se desviaron las instancias (de entrenamiento o de validación) de su valor real.
def _plot_confusion_matrix(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature):
plt.figure(figsize=(14, 10), dpi= 80, facecolor='w', edgecolor='k')
plt.subplot(2, 2, 1)
title = f'Entrenamiento (sin normalizar) {x_feature}-{y_feature}'
plot_confusion_matrix(confusion_matrix(y_train, model.predict(X_train_feature)),
classes=breast_cancer_data.target_names,
title=title)
plt.subplot(2, 2, 3)
title = f'Entrenamiento (normalizando) {x_feature}-{y_feature}'
plot_confusion_matrix(confusion_matrix(y_train, model.predict(X_train_feature)),
classes=breast_cancer_data.target_names, normalize=True,
title=title)
plt.subplot(2, 2, 2)
title = f'Validación (sin normalizar) {x_feature}-{y_feature}'
plot_confusion_matrix(confusion_matrix(y_val, model.predict(X_val_feature)),
classes=breast_cancer_data.target_names,
title=title)
plt.subplot(2, 2, 4)
title = f'Validación (normalizando) {x_feature}-{y_feature}'
plot_confusion_matrix(confusion_matrix(y_val, model.predict(X_val_feature)),
classes=breast_cancer_data.target_names, normalize=True,
title=title)
plt.show()
_plot_confusion_matrix(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature)
def plot_frontera_decision(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature):
plt.figure(figsize=(14, 5), dpi=80, facecolor='w', edgecolor='k')
xx, yy, Z = classifier_boundary(np.r_[X_train_feature, X_val_feature], model)
cmap_dots = ListedColormap(['tomato', 'dodgerblue'])
cmap_back = ListedColormap(['lightcoral', 'skyblue'])
# Conjunto de entrenamiento
plt.subplot(1, 2, 1)
plt.pcolormesh(xx, yy, Z, cmap=cmap_back)
plt.scatter(X_train_feature[:, 0], X_train_feature[:, 1], c=y_train, cmap=cmap_dots, edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title(f"Conjunto de Entrenamiento {x_feature}-{y_feature}")
# Conjunto de validación
plt.subplot(1, 2, 2)
plt.pcolormesh(xx, yy, Z, cmap=cmap_back)
plt.scatter(X_val_feature[:, 0], X_val_feature[:, 1], c=y_val, cmap=cmap_dots, edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title(f"Conjunto de Validación {x_feature}-{y_feature}")
plt.show()
plot_frontera_decision(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature)
Probamos Perceptron aumentando la cantidad de iteraciones maximas(pues el algoritmo original itera hasta que no hay datos en el set de entrenamiento mal clasificados)
penalty = 'l1' # Tipo de regularización: l1 (valor absoluto), l2 (cuadrados), elasticnet (l1 + l2).
alpha = 0.1 # ParÔmetro de regularización. También denominado como parÔmetro `lambda`.
max_iter = 1000 # Cantidad mƔxima de iteraciones del algoritmo
model = Perceptron(penalty=penalty, alpha=alpha, max_iter=max_iter)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
Se observa que la precicio del ajuste mejora de 0.56 a 0.86 y 0.49 a 0.85 para los set de entrenamiento y validación respectivamente
_plot_confusion_matrix(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature)
Las matrices de confusion muestran menos errores
plot_frontera_decision(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature)
Las fronteras tambien separan de manera mas clara
Tras varias pruebas encontramos que el termino de regularización $\alpha$ = 0.5 da una mejor precisión
penalty = 'l1' # Tipo de regularización: l1 (valor absoluto), l2 (cuadrados), elasticnet (l1 + l2).
max_iter = 1000 # Cantidad mƔxima de iteraciones del algoritmo
model = Perceptron(penalty=penalty, alpha=0.5, max_iter=max_iter)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
plot_frontera_decision(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature)
Por ultimo probamos otros valores para el parametro penalty, pero no se logro mejorar la precición
penalty = 'l2' # Tipo de regularización: l1 (valor absoluto), l2 (cuadrados), elasticnet (l1 + l2).
model = Perceptron(penalty=penalty, alpha=0.5, max_iter=1000)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
penalty = 'elasticnet' # Tipo de regularización: l1 (valor absoluto), l2 (cuadrados), elasticnet (l1 + l2).
model = Perceptron(penalty=penalty, alpha=0.5, max_iter=1000)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
penalty = 'l1'# Tipo de regularización: l1 (valor absoluto), l2 (cuadrados).
alpha = 0.01 # ParÔmetro de regularización. También denominado como parÔmetro `lambda`. Debe ser mayor que 0.
model = LogisticRegression(penalty=penalty, C=1./alpha)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
penalty = 'l1'# Tipo de regularización: l1 (valor absoluto), l2 (cuadrados).
alpha = 1000 # ParÔmetro de regularización. También denominado como parÔmetro `lambda`. Debe ser mayor que 0.
model = LogisticRegression(penalty=penalty, C=1./alpha)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
Un valor de $\alpha$ muy alto genera una baja en la precición
penalty = 'l2' #l2 (cuadrados).
alpha = 0.001
model = LogisticRegression(penalty=penalty, C=1./alpha)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
Cambiar el tipo de penalty no afecta el mejor resultado de precición
_plot_confusion_matrix(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature)
plot_frontera_decision(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature)
n_neighbors = 4 # Cantidad de vecinos a tener en cuenta
metric = 'cosine' # Medida de distancia. Algunas opciones: cosine, euclidean, manhattan.
model = KNeighborsClassifier(n_neighbors=n_neighbors, metric=metric)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
n_neighbors = 10
metric = 'manhattan'
model = KNeighborsClassifier(n_neighbors=n_neighbors, metric=metric)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
n_neighbors = 15
metric = 'euclidean'
model = KNeighborsClassifier(n_neighbors=n_neighbors, metric=metric)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
_plot_confusion_matrix(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature)
plot_frontera_decision(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature)
Probamos con otros features
Probamos KNeighborsClassifier
# Seleccionamos dos atributo de los listados en el apartado anterior, uno para el eje x y otro para el eje y
x_feature = 'mean perimeter'
y_feature = 'mean area'
x_feature_col = feature_map[x_feature]
y_feature_col = feature_map[y_feature]
X_train_feature = X_train[:, [x_feature_col, y_feature_col]]
X_val_feature = X_val[:, [x_feature_col, y_feature_col]]
n_neighbors = 15
metric = 'cosine'
model = KNeighborsClassifier(n_neighbors=n_neighbors, metric=metric)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
_plot_confusion_matrix(X_train_feature, y_train, X_val_feature, y_val, x_feature, y_feature)
plt.figure(figsize=(14, 5), dpi=80, facecolor='w', edgecolor='k')
xx, yy, Z = classifier_boundary(np.r_[X_train_feature, X_val_feature], model, h=1)
cmap_dots = ListedColormap(['tomato', 'dodgerblue'])
cmap_back = ListedColormap(['lightcoral', 'skyblue'])
# Conjunto de entrenamiento
plt.subplot(1, 2, 1)
plt.pcolormesh(xx, yy, Z, cmap=cmap_back)
plt.scatter(X_train_feature[:, 0], X_train_feature[:, 1], c=y_train, cmap=cmap_dots, edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title(f"Conjunto de Entrenamiento {x_feature}-{y_feature}")
# Conjunto de validación
plt.subplot(1, 2, 2)
plt.pcolormesh(xx, yy, Z, cmap=cmap_back)
plt.scatter(X_val_feature[:, 0], X_val_feature[:, 1], c=y_val, cmap=cmap_dots, edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title(f"Conjunto de Validación {x_feature}-{y_feature}")
plt.show()
Ahora veremos clasificación multiclase. Muy similar al caso anterior, con la diferencia de que en este caso hay mÔs de dos etiquetas posibles para clasificación. Se utilizarÔ el método one-vs-all (o también one-vs-rest) para hacer posible la clasificación.
Una vez mƔs tenemos que decidir dos features para poder visualizar los modelos.
iris_data = load_iris()
# Utilizamos aproximadamente 80% de los datos para entrenamiento y 20% para validación
shuff_data = np.random.permutation(150)
shuff_train = shuff_data[:120]
shuff_val = shuff_data[120:]
X_train = iris_data['data'][shuff_train]
X_val = iris_data['data'][shuff_val]
y_train = iris_data['target'][shuff_train]
y_val = iris_data['target'][shuff_val]
feature_map = {feature: idx for idx, feature in enumerate(iris_data['feature_names'])}
print(iris_data['DESCR'])
print("Listado de atributos\n====================")
for feature in iris_data['feature_names']:
print("- %s" % feature)
# Seleccionamos dos atributo de los listados en el apartado anterior, uno para el eje x y otro para el eje y
# TODO: Cambiar los atributos y ver como se modifica el resultado
x_feature = 'sepal length (cm)'
y_feature = 'sepal width (cm)'
x_feature_col = feature_map[x_feature]
y_feature_col = feature_map[y_feature]
X_train_feature = X_train[:, [x_feature_col, y_feature_col]]
X_val_feature = X_val[:, [x_feature_col, y_feature_col]]
penalty = 'l1' # Tipo de regularización: l1 (valor absoluto), l2 (cuadrados).
alpha = 0.01 # ParÔmetro de regularización. También denominado como parÔmetro `lambda`. Debe ser mayor que 0.
model = LogisticRegression(penalty=penalty, C=1./alpha, multi_class='ovr')
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
plt.figure(figsize=(14, 10), dpi= 80, facecolor='w', edgecolor='k')
plt.subplot(2, 2, 1)
plot_confusion_matrix(confusion_matrix(y_train, model.predict(X_train_feature)),
classes=iris_data.target_names,
title='Matriz de confusión para entrenamiento (sin normalizar)')
plt.subplot(2, 2, 3)
plot_confusion_matrix(confusion_matrix(y_train, model.predict(X_train_feature)),
classes=iris_data.target_names, normalize=True,
title='Matriz de confusión para entrenamiento (normalizando)')
plt.subplot(2, 2, 2)
plot_confusion_matrix(confusion_matrix(y_val, model.predict(X_val_feature)),
classes=iris_data.target_names,
title='Matriz de confusión para validación (sin normalizar)')
plt.subplot(2, 2, 4)
plot_confusion_matrix(confusion_matrix(y_val, model.predict(X_val_feature)),
classes=iris_data.target_names, normalize=True,
title='Matriz de confusión para validación (normalizando)')
plt.show()
plt.figure(figsize=(14, 5), dpi=80, facecolor='w', edgecolor='k')
xx, yy, Z = classifier_boundary(np.r_[X_train_feature, X_val_feature], model)
cmap_dots = ListedColormap(['tomato', 'dodgerblue', 'goldenrod'])
cmap_back = ListedColormap(['lightcoral', 'skyblue', 'palegoldenrod'])
# Conjunto de entrenamiento
plt.subplot(1, 2, 1)
plt.pcolormesh(xx, yy, Z, cmap=cmap_back)
plt.scatter(X_train_feature[:, 0], X_train_feature[:, 1], c=y_train, cmap=cmap_dots, edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Conjunto de Entrenamiento")
plt.xlabel(x_feature)
plt.ylabel(y_feature)
# Conjunto de validación
plt.subplot(1, 2, 2)
plt.pcolormesh(xx, yy, Z, cmap=cmap_back)
plt.scatter(X_val_feature[:, 0], X_val_feature[:, 1], c=y_val, cmap=cmap_dots, edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Conjunto de Validación")
plt.xlabel(x_feature)
plt.ylabel(y_feature)
plt.show()
def get_accuracy_knc(X_train_feature, y_train, X_val_feature, y_val, n_neighbors, metric):
model = KNeighborsClassifier(n_neighbors=n_neighbors, metric=metric)
model.fit(X_train_feature, y_train)
training_accuracy_score = accuracy_score(y_train, model.predict(X_train_feature))
val_accuracy_score = accuracy_score(y_val, model.predict(X_val_feature))
return training_accuracy_score, val_accuracy_score
x = range(1, 50)
for metric in ['euclidean', 'cosine', 'manhattan']:
accuracy_training = []
accuracy_val = []
for n_neighbors in x:
accuracy_training.append(get_accuracy_knc(X_train_feature, y_train, X_val_feature, y_val, n_neighbors, metric)[0])
accuracy_val.append(get_accuracy_knc(X_train_feature, y_train, X_val_feature, y_val, n_neighbors, metric)[1])
plt.figure(figsize=(14, 5), dpi= 80, facecolor='w', edgecolor='k')
plt.plot(x, accuracy_training, label='Training')
plt.plot(x, accuracy_val, label='Validation')
plt.title(f" Accuracy for features {x_feature} {y_feature} - {metric}")
plt.legend(loc='upper right')
plt.xlabel("neighbors")
plt.ylabel("Accuracy")
plt.show()
20 neighbors + distancia 'euclidean' parece dar una buena precición
n_neighbors = 20 # Cantidad de vecinos a tener en cuenta
metric = 'euclidean' # Medida de distancia. Algunas opciones: cosine, euclidean, manhattan.
model = KNeighborsClassifier(n_neighbors=n_neighbors, metric=metric)
model.fit(X_train_feature, y_train)
print('Exactitud para entrenamiento: %.2f' % accuracy_score(y_train, model.predict(X_train_feature)))
print('Exactitud para validación: %.2f' % accuracy_score(y_val, model.predict(X_val_feature)))
plt.figure(figsize=(14, 10), dpi= 80, facecolor='w', edgecolor='k')
plt.subplot(2, 2, 1)
plot_confusion_matrix(confusion_matrix(y_train, model.predict(X_train_feature)),
classes=iris_data.target_names,
title='Matriz de confusión para entrenamiento (sin normalizar)')
plt.subplot(2, 2, 3)
plot_confusion_matrix(confusion_matrix(y_train, model.predict(X_train_feature)),
classes=iris_data.target_names, normalize=True,
title='Matriz de confusión para entrenamiento (normalizando)')
plt.subplot(2, 2, 2)
plot_confusion_matrix(confusion_matrix(y_val, model.predict(X_val_feature)),
classes=iris_data.target_names,
title='Matriz de confusión para validación (sin normalizar)')
plt.subplot(2, 2, 4)
plot_confusion_matrix(confusion_matrix(y_val, model.predict(X_val_feature)),
classes=iris_data.target_names, normalize=True,
title='Matriz de confusión para validación (normalizando)')
plt.show()
plt.figure(figsize=(14, 5), dpi=80, facecolor='w', edgecolor='k')
xx, yy, Z = classifier_boundary(np.r_[X_train_feature, X_val_feature], model)
cmap_dots = ListedColormap(['tomato', 'dodgerblue', 'goldenrod'])
cmap_back = ListedColormap(['lightcoral', 'skyblue', 'palegoldenrod'])
# Conjunto de entrenamiento
plt.subplot(1, 2, 1)
plt.pcolormesh(xx, yy, Z, cmap=cmap_back)
plt.scatter(X_train_feature[:, 0], X_train_feature[:, 1], c=y_train, cmap=cmap_dots, edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Conjunto de Entrenamiento")
plt.xlabel(x_feature)
plt.ylabel(y_feature)
# Conjunto de validación
plt.subplot(1, 2, 2)
plt.pcolormesh(xx, yy, Z, cmap=cmap_back)
plt.scatter(X_val_feature[:, 0], X_val_feature[:, 1], c=y_val, cmap=cmap_dots, edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Conjunto de Validación")
plt.xlabel(x_feature)
plt.ylabel(y_feature)
plt.show()